﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;

namespace fwatch
{
	class Program
	{
		static string[] usage = {
			"File Watch",
			"    Watches multiple files for changes and displays new lines",
			"Usage:",
			"    fwatch [OPTIONS]",
			"Options:",
			"    -file FILENAME      -- file to monitor",
			"    -filter REGEX       -- filter lines matching the pattern",
			"    -colorFilter REGEX  -- highlight line with color",
			"    -color CONSOLECOLOR -- color to highlight. (Use with -colorFilter)"
		};

		static void Usage()
		{
			foreach (string s in usage)
			{
				Console.WriteLine(s);
			}
		}

		static List<FileInfo> files = new List<FileInfo>();
		static List<Regex> filters = new List<Regex>();
		static List<Regex> colorFilters = new List<Regex>();
		static List<ConsoleColor> colors = new List<ConsoleColor>();

		static void Main(string[] args)
		{
			if (args.Length == 0)
			{
				Usage();
				return;
			}

			string opt = "";
			for (int i = 0; i < args.Length; i++)
			{
				if (args[i][0] == '-')
				{
					opt = args[i].Substring(1).ToLower();
					continue;
				}

				switch (opt)
				{
					case "file":
						files.Add(new FileInfo(args[i]));
						break;

					case "filter":
						filters.Add(new Regex(args[i]));
						break;

					case "colorfilter":
						colorFilters.Add(new Regex(args[i]));
						break;

					case "color":
						colors.Add((ConsoleColor)Enum.Parse(typeof(ConsoleColor), args[i]));
						break;
				}
			}

			// check access

			for (int i = 0; i < files.Count; i++)
			{
				FileInfo fi = files[i];
				if (fi.Exists)
				{
					Console.WriteLine("watching {0}: {1}", i + 1, fi.FullName);
				}
				else
				{
					Console.WriteLine("watching {0}: {1} -- doesn't exist", i + 1, fi.FullName);
				}
			}

			while (true)
			{
				for (int i = 0; i < files.Count; i++)
				{
					FileInfo fi = files[i];

					FileInfo finew = new FileInfo(fi.FullName);
					if (finew.Length > fi.Length)
					{
						PrintChunk((i + 1).ToString(), fi.FullName, fi.Length);
						files[i] = finew;
					}
				}
				System.Threading.Thread.Sleep(500);
			}
		}

		private static void PrintChunk(string name, string fname, long startLength)
		{
			using (FileStream st = new FileStream(fname, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
			{
				st.Position = startLength;
				using (StreamReader r = new StreamReader(st))
				{
					while (!r.EndOfStream)
					{
						string line = r.ReadLine();

						if (!MatchFilter(line))
						{
							PrintColored(name, line);
						}
					}
				}
			}
		}

		private static void PrintColored(string name, string line)
		{
			ConsoleColor oldColor = Console.ForegroundColor;

			for (int i = 0; i < colorFilters.Count; i++)
			{
				if (!colorFilters[i].IsMatch(line))
				{
					continue;
				}

				if (i < colors.Count)
				{
					Console.ForegroundColor = colors[i];
				}
				else
				{
					Console.ForegroundColor = ConsoleColor.Cyan;
				}

				break;
			}

			Console.WriteLine(name + ": " + line);
			Console.ForegroundColor = oldColor;
		}

		private static bool MatchFilter(string line)
		{
			foreach (Regex rex in filters)
			{
				if (rex.IsMatch(line))
				{
					return true;
				}
			}
			return false;
		}
	}
}
